package com.zhuky;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用 synchronized wait notify 模拟队列
 *
 * @author zhu
 */
public class MyQueue {

    /** 1. 创建一个列表 */
    private LinkedList<Object> list = new LinkedList<>();

    /** 2. 创建一个计数器负责管理列表的长度 */
    private AtomicInteger counter = new AtomicInteger(0);

    /** 3. 创建一个锁对象 */
    private Object lock = new Object();

    /** 4. 设置队列中元素数量的最大最小值 */
    private int minSize = 0;
    private int maxSize;

    public MyQueue(int maxSize){
        this.maxSize = maxSize;
    }

    /**
     * 向队列中存放元素
     * @param o
     */
    public void put(Object o){
        /** 先加锁 */
        synchronized (lock) {
            /**
             * 如果队列满了 调用wait方法使线程进入等待状态
             */
            if (counter.get() == maxSize) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            /**
             * 如果队列没有满，需要做3件事
             * 1. 添加元素
             * 2. 计数加一
             * 3. 唤醒take线程
             */
            list.add(o);
            counter.incrementAndGet();
            System.out.println("添加元素：" + o);
            lock.notify();
        }
    }

    /**
     * 从队列中去出元素
     */
    public Object take(){
        Object o = null;
        /** 先加锁 */
        synchronized (lock) {
            /** 判断队列是否为空 */
            if (counter.get() == minSize){
                /**
                 * 如果队列为空: 进入等待状态
                 */
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            /**
             * 如果队列不为空，做三件事
             * 1. 取出队列中的第一个元素
             * 2. 计数减一
             * 3. 发送通知
             */
            o = list.removeFirst();
            counter.decrementAndGet();
            System.out.println("取出元素：" + o);
            lock.notify();
        }
        return o;
    }
    /**
     * 求当前队列中元素的数量
     */
    public int size(){
        return this.counter.get();
    }

    public static void main(String[] args) {
        MyQueue myQueue = new MyQueue(5);
        myQueue.put("a");
        myQueue.put("b");
        myQueue.put("c");
        myQueue.put("d");
        myQueue.put("e");

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                myQueue.put("f");
                myQueue.put("g");
            }
        }, "t1");

        t1.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Object o1 = myQueue.take();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Object o2 = myQueue.take();
            }
        }, "t2");
        t2.start();
    }
}
